package com.harboursoftware.xstorage.results;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

/**
 * //TODO: 创建一ErrorResults的工具类用于创建ErrorResult
 * @author Simon Leung
 * @since 0.1
 */
public class ErrorResult extends XMLResult {
    public enum Type {
        ACCESS_DENIED,
        INVALID_BUCKET_NAME,
        BUCKET_ALREADY_EXISTS,
        BUCKET_ALREADY_OWNED_BY_YOU,
        INTERNAL_ERROR,
        NO_SUCH_BUCKET,
        BUCKET_NOT_EMPTY,
        NO_SUCH_KEY,
        INVALID_DIGEST,
        INCOMPLETE_BODY,
        INVALID_ARGUMENT,
        INVALID_ACCESS_KEY_ID,
        SIGNATURE_DOES_NOT_MATCH
    }
  
    private String code = "";
    private String message = "";
	private Map<String, String> otherInfos;

    private ErrorResult(String code, String message, int status) {
        this.code = code;
        this.message = message;
        this.status = status;
    }
    
    public static ErrorResult create(Type type) {
        switch(type) {
            case ACCESS_DENIED :
                return new ErrorResult("AccessDenied", "Access Denied", 403);
            case INVALID_BUCKET_NAME : 
                return new ErrorResult("InvalidBucketName", "The specified bucket is not valid.", 400);
            case BUCKET_ALREADY_EXISTS :
                return new ErrorResult("BucketAlreadyExists", "The requested bucket name is not available. The bucket namespace is shared by all users of the system. Please select a different name and try again.", 409);
            case BUCKET_ALREADY_OWNED_BY_YOU :
                return new ErrorResult("BucketAlreadyOwnedByYou", "Your previous request to create the named bucket succeeded and you already own it.", 409);
            case INTERNAL_ERROR :
                return new ErrorResult("InternalError", "We encountered an internal error. Please try again.", 500);
            case NO_SUCH_BUCKET :
                return new ErrorResult("NoSuchBucket", "The specified bucket does not exist.", 404);
            case BUCKET_NOT_EMPTY :
                return new ErrorResult("BucketNotEmpty", "The bucket you tried to delete is not empty.", 409);
            case NO_SUCH_KEY :
                return new ErrorResult("NoSuchKey", "The specified key does not exist.", 404);
            case INVALID_DIGEST :
                return new ErrorResult("InvalidDigest", "The Content-MD5 you specified was an invalid.", 400);
            case INCOMPLETE_BODY :
                return new ErrorResult("IncompleteBody", "You did not provide the number of bytes specified by the Content-Length HTTP header", 400);
            case INVALID_ARGUMENT :
                return new ErrorResult("InvalidArgument", "Invalid Argument", 400);
            case INVALID_ACCESS_KEY_ID:
                return new ErrorResult("InvalidAccessKeyId", "The AWS Access Key Id you provided does not exist in our records.", 403);
            case SIGNATURE_DOES_NOT_MATCH:
                return new ErrorResult("SignatureDoesNotMatch", "The request signature we calculated does not match the signature you provided. Check your key and signing method.", 403);
            default :
                throw new IllegalArgumentException("no such ErrorResponse");
        }
    }
    
    public static ErrorResult createNoSuckBucket(String bucketName) {
        ErrorResult errorResult = ErrorResult.create(ErrorResult.Type.NO_SUCH_BUCKET);
        errorResult.addOtherInfo("BucketName", bucketName);
        return errorResult;
    }

    @Override
    public String toXML() {
        StringBuilder strBuilder = new StringBuilder(512);
        strBuilder.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
        .append("<Error>")
        .append("<Code>")
        .append(code)
        .append("</Code>")
        .append("<Message>")
        .append(message)
        .append("</Message>");
        if(otherInfos != null) {
        	for(Entry<String, String> entry : otherInfos.entrySet()) {
        		strBuilder.append("<")
        		.append(entry.getKey())
        		.append(">")
        		.append(entry.getValue())
        		.append("</")
        		.append(entry.getKey())
        		.append(">");
        	}
        }
        strBuilder.append("<RequestId>")
        .append(xAmzId2)
        .append("</RequestId>")
        .append("<HostId>")
        .append(xAmzRequestId)
        .append("</HostId>")
        .append("</Error>");
        return strBuilder.toString();
    }

    @Override
    public String toString() {
        return "ErrorResponse [code=" + code + ", message=" + message + ", status=" + status + "]";
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

	@SuppressWarnings("unchecked")
	public Map<String, String> getOtherInfos() {
		return otherInfos == null ? Collections.EMPTY_MAP : otherInfos;
	}

	public void setOtherInfos(Map<String, String> otherInfos) {
		this.otherInfos = otherInfos;
	}
    
    public void addOtherInfo(String name, String message) {
    	if(otherInfos == null) {
    		otherInfos = new HashMap<String, String>();
    	}
    	otherInfos.put(name, message);
    }
}
